import {
  SelectProps,
  DISPLAY_NAME_SELECT,
  getSelectClassNames,
  SelectContext,
  ISelectContext,
} from './config'
import React, {
  FC,
  useState,
  useRef,
  FunctionComponentElement,
  useEffect,
} from 'react'
import Input from '../Input'
import Icon from '../Icon'
import useClickOutside from '../../hooks/useClickOutside'
import Transition from '../Transition/transition'
import { SelectOptionProps } from './Option'

export const Select: FC<SelectProps> = props => {
  const {
    defaultValue,
    placeholder,
    children,
    multiple,
    name,
    disabled,
    onChange,
    onVisibleChange,
  } = props

  const [selectedValues, setSelectedValues] = useState<string[]>(
    Array.isArray(defaultValue) ? defaultValue : []
  )
  const [menuOpen, setOpen] = useState(false)
  const [value, setValue] = useState(
    typeof defaultValue === 'string' ? defaultValue : ''
  )

  const selectClasses = getSelectClassNames(props, () => {
    return {
      'menu-is-open': menuOpen,
    }
  })

  const handleOptionClick = (value: string, isSelected?: boolean) => {
    // update value
    if (!multiple) {
      setOpen(false)
      setValue(value)
      if (onVisibleChange) {
        onVisibleChange(false)
      }
    } else {
      // 有值时写入一个空格以隐藏input的placeholder
      setValue('')
    }
    let updatedValues = [value]
    // click again to remove selected when is multiple mode
    if (multiple) {
      updatedValues = isSelected
        ? selectedValues.filter(v => v !== value)
        : [...selectedValues, value]
      setSelectedValues(updatedValues)
      // 无值时显示input的placeholder
      // updatedValues.length === 0 && setValue('')
    }
    if (onChange) {
      onChange(value, updatedValues)
    }
  }
  const passedContext: ISelectContext = {
    onSelect: handleOptionClick,
    selectedValues: selectedValues,
    multiple: multiple,
  }
  const handleClick = (e: React.MouseEvent) => {
    e.preventDefault()
    if (!disabled) {
      setOpen(!menuOpen)
      if (onVisibleChange) {
        onVisibleChange(!menuOpen)
      }
    }
  }
  const generateOptions = () => {
    return React.Children.map(children, (child, i) => {
      const childElement = child as FunctionComponentElement<SelectOptionProps>
      if (childElement.type.displayName === 'Option') {
        return React.cloneElement(childElement, {
          index: `select-${i}`,
        })
      } else {
        console.error(
          'Warning: Select has a child which is not a Option component'
        )
      }
    })
  }

  const input = useRef<HTMLInputElement>(null)
  const containerRef = useRef<HTMLDivElement>(null)
  const containerWidth = useRef(0)
  useEffect(() => {
    // focus input
    if (input.current) {
      input.current.focus()
      if (multiple && selectedValues.length > 0) {
        input.current.placeholder = ''
      } else {
        if (placeholder) input.current.placeholder = placeholder
      }
    }
  }, [selectedValues, multiple, placeholder])
  useEffect(() => {
    if (containerRef.current) {
      containerWidth.current = containerRef.current.getBoundingClientRect().width
    }
  })
  useClickOutside(containerRef, () => {
    setOpen(false)
    if (onVisibleChange && menuOpen) {
      onVisibleChange(false)
    }
  })

  return (
    <div className={selectClasses} ref={containerRef}>
      <div className="select-input" onClick={handleClick}>
        <Input
          comRef={input}
          placeholder={placeholder}
          value={value}
          readOnly
          icon="angle-down"
          disabled={disabled}
          name={name}
        />
      </div>
      <SelectContext.Provider value={passedContext}>
        <Transition in={menuOpen} animation="zoom-in-top" timeout={300}>
          <ul className="select-dropdown">{generateOptions()}</ul>
        </Transition>
      </SelectContext.Provider>
      {multiple && (
        <div
          className="selected-tags"
          style={{ maxWidth: containerWidth.current - 32 }}>
          {selectedValues.map((value, index) => {
            return (
              <span className="tag" key={`tag-${index}`}>
                {value}
                <Icon
                  icon="times"
                  onClick={() => {
                    handleOptionClick(value, true)
                  }}
                />
              </span>
            )
          })}
        </div>
      )}
    </div>
  )
}
Select.displayName = DISPLAY_NAME_SELECT

Select.defaultProps = {
  name: 'select',
  placeholder: '请选择',
}

export default Select
